package stack;


import org.junit.Test;

//栈实现计算器   作业＋()完成
public class Calculator {

    @Test
    public  void test(){
        //3+2*6-4
        //定义一个数栈 和一个字符栈
        ArrayStack2 numberStack=new ArrayStack2(10);
        ArrayStack2 operaStack=new ArrayStack2(10);
        //定义接受的值
        int num1=0;
        int num2=0;
        int opera=0; //操作符 可以用char
        int res=0; //返回结果
        int index=0;//定义一个辅助指针
        String str="100000+1000*2000-50000";  //多为数的问题 思路计算利用keepStr来保存这些多位数
        //字符串是以\0结尾
        System.out.println("str长度:"+str.length());
        String keepNum="";
        char ch=' ';//分词扫描得到的cahr 保存到ch
        while(true){
             ch=str.subSequence(index, index+1).charAt(0); //截取str的字符
            //判断是不是操作符
            if(operaStack.isOpera(ch)){
                //再判断 符号栈里是不是有操作符 如果没有直接入栈，有再判断符号优先级
                if(operaStack.isEmpty()){
                    operaStack.push(ch);
                }else {
                    //和前一个操作栈里的字符进行优先级判断
                    //如果当前优先级大于前一个
                    if(operaStack.priority(ch)>operaStack.priority(operaStack.peek())){
                        operaStack.push(ch);
                    }else{
                        //当前的优先级小于之前的优先级
                        //那么从数字栈中取出两个值，操作栈中取出一个值进行计算。计算的值再入数字栈，再把当前操作符入字符栈
                        num1=numberStack.pop();
                        num2=numberStack.pop();
                        opera=operaStack.pop();
                        res=numberStack.cal(num1, num2, opera);
                        numberStack.push(res);
                        operaStack.push(ch); //当前操作符ch入字符栈
                    }
                }
                //如果是数字
            }else{
                //定义一个字符串来拼接数字
                keepNum+=ch;
                //判断多位数,判断下一个字符是不是数字，如果是最后一个数字了，就直接入栈
                if(index==str.length()-1){
                    numberStack.push(Integer.parseInt(keepNum));
                }else{
                    //判断下一个字符是不是数字，如果是数字就继续扫描,keepNum拼接，如果是运算符就入栈
                    if(operaStack.isOpera(str.substring(index+1,index+2).charAt(0))){
                        numberStack.push(Integer.parseInt(keepNum));
                        keepNum="";
                    }
                }
//                numberStack.push(ch-48);//因为字符'1'=48+1  ASCll码
            }
            index++; //往下遍历
            if(index>=str.length()){
                break; //遍历到最后一个字符后就退出程序
            }
        }
        //然后进行数字栈，符号栈遍历，如果符号栈遍历完之后，那么数字栈中就只有最后一个返回值了
        while(true){
            if(operaStack.isEmpty()){
               break;
            }
            num1=numberStack.pop();
            num2=numberStack.pop();
            opera=operaStack.pop();
            res=numberStack.cal(num1, num2, opera);
            numberStack.push(res);
        }
        System.out.printf("表达式%s=%d",str,numberStack.pop());
    }

}
//数组模拟栈
class ArrayStack2{

    private int maxSize;//栈的最大值
    private int top=-1; //栈指向
    private int[] stack;//模拟栈数组

    public ArrayStack2(int maxSize) {
        this.maxSize = maxSize;
        stack=new int[maxSize];
    }
    //偷看栈顶的值
    public int peek(){
        return stack[top];
    }

    //判断栈满
    public  boolean isFull(){
        return top==maxSize-1;  //top->最顶部
    }
    //判断栈空
    public  boolean isEmpty(){
        return top==-1;
    }
    //入栈 push  往数组里添加数据  先判断栈是否满了
    public void push(int value){
        if(isFull()){
            System.out.println("栈满了~ ~");
            return;
        }
        top++;
        stack[top]=value;
    }
    //出栈 pop  先进后出   顶部先出  先判断栈是否为空
    public int pop(){
        if(isEmpty()){
            throw  new RuntimeException("栈空~ ~");
        }
        int value=stack[top];
        top--;
        return value;
    }
    //遍历栈
    public  void list(){
        //先判断栈是否为空
        if(isEmpty()){
            System.out.println("栈空~ ~");
            return;
        }
        //先进后出  从最后往前遍历
        for (int i =top; i>=0 ; i--) {
            System.out.printf("stack[%d]=%d\n",i,stack[i]);
        }
    }

    //返回运算符的优先级，优先级是程序员来定义的，优先级用数字来表示
    //数字越大，则优先级越高
    public int priority(int opera){
        if(opera=='*'||opera=='/'){
            return 1;
        }else if(opera=='+'||opera=='-') {
            return 0;
        }else {
            return -1; //假设当前的表达式只有+ - * /
        }
    }

    //判断是不是一个运算符
    public boolean isOpera(char val){
        return val=='*'||val=='/'||val=='+'||val=='-';
    }
    //计算方法
    public int cal(int num1,int num2,int opera){
        int res=0; //用于计算的结果
        switch (opera){
            case '+':
               res=num1+num2;break;
            case '-':
                res=num2-num1;break;    //stack是先进后出
            case '*':
                res=num1*num2;break;
            case '/':
                res=num2/num1;break;
            default:
                break;
        }
        return res;
    }

}
